home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS26.ADF / SoundScape / LatticeExamples / crossfade.c < prev    next >
C/C++ Source or Header  |  1989-01-26  |  11KB  |  526 lines

  1. /*    CROSSFADE.C    Cross fade loop generator for the
  2.             SoundScape sampler.
  3.  
  4.     (c) 1987     Todor Fay
  5. */
  6.     
  7. #include "exec/exec.h"
  8. #include "exec/types.h"
  9. #include "intuition/intuition.h"
  10. #include "soundscape.h"
  11. #include "sampler.h"
  12.  
  13. /*    Cross Fade Icon for Patch Panel: */
  14.  
  15. UWORD crossfadedata[] = {    /* 36 x 11 */ 
  16. 0,    0,    0,    
  17. 16383,    65535,    49152,    
  18. 511,    65528,    0,    
  19. 15887,    65287,    49152,    
  20. 16368,    24831,    49152,    
  21. 16383,    40959,    49152,    
  22. 16368,    24831,    49152,    
  23. 15887,    65287,    49152,    
  24. 511,    65528,    0,    
  25. 16383,    65535,    49152,    
  26. 0,    0,    0,    
  27. 65535,    65535,    61440,    
  28. 49152,    4,    12288,    
  29. 49152,    57544,    12288,    
  30. 49153,    61700,    28672,    
  31. 55792,    24812,    61440,    
  32. 65535,    40959,    61440,    
  33. 55792,    24812,    61440,    
  34. 49153,    61444,    28672,    
  35. 49152,    57544,    12288,    
  36. 49152,    4,    12288,    
  37. 65535,    65535,    61440,    
  38. };
  39.  
  40. struct Image crossfadeimage = 
  41.     { 0,0,36,11,2,crossfadedata,3,0,0 };
  42.  
  43. /*    Edit window.  This has the gadgets for selecting 
  44.     sampler channel and octave, and Doing and Undoing
  45.     the cross fade.  These intuition data structures
  46.     were generated with Power Windows.
  47. */
  48.  
  49. USHORT BorderVectors1[] = {0,0,107,0,107,10,0,10,0,0};
  50. struct Border Border1 = {
  51.     -2,-1,
  52.     3,0,JAM1,
  53.     5,
  54.     BorderVectors1,
  55.     NULL
  56. };
  57.  
  58. struct IntuiText IText1 = {
  59.     1,0,JAM2,
  60.     33,1,
  61.     NULL,
  62.     "Undo",
  63.     NULL
  64. };
  65.  
  66. struct Gadget UndoGadget = {
  67.     NULL,
  68.     23,55,
  69.     104,9,
  70.     GADGHCOMP,
  71.     RELVERIFY,
  72.     BOOLGADGET,
  73.     (APTR)&Border1,
  74.     NULL,
  75.     &IText1,
  76.     0,
  77.     NULL,
  78.     8,
  79.     NULL
  80. };
  81.  
  82. UBYTE SIBuffer7[4] =
  83.     "5";
  84. struct StringInfo GadgetSI7 = {
  85.     SIBuffer7,
  86.     NULL,
  87.     0,
  88.     4,
  89.     0,
  90.     0,0,0,0,0,
  91.     0,
  92.     5,
  93.     NULL
  94. };
  95.  
  96. USHORT BorderVectors2[] = {0,0,35,0,35,9,0,9,0,0};
  97. struct Border Border2 = {
  98.     -2,-1,
  99.     1,0,JAM1,
  100.     5,
  101.     BorderVectors2,
  102.     NULL
  103. };
  104.  
  105. struct IntuiText IText2 = {
  106.     2,0,JAM2,
  107.     -60,0,
  108.     NULL,
  109.     "Octave",
  110.     NULL
  111. };
  112.  
  113. struct Gadget OctaveGadget = {
  114.     &UndoGadget,
  115.     95,28,
  116.     32,8,
  117.     GADGHCOMP,
  118.     LONGINT+RELVERIFY+STRINGCENTER,
  119.     STRGADGET,
  120.     (APTR)&Border2,
  121.     NULL,
  122.     &IText2,
  123.     0,
  124.     (APTR)&GadgetSI7,
  125.     7,
  126.     NULL
  127. };
  128.  
  129. UBYTE SIBuffer6[4] =
  130.     "1";
  131. struct StringInfo GadgetSI6 = {
  132.     SIBuffer6,
  133.     NULL,
  134.     0,
  135.     4,
  136.     0,
  137.     0,0,0,0,0,
  138.     0,
  139.     1,
  140.     NULL
  141. };
  142.  
  143. USHORT BorderVectors3[] = {0,0,35,0,35,9,0,9,0,0};
  144. struct Border Border3 = {
  145.     -2,-1,
  146.     1,0,JAM1,
  147.     5,
  148.     BorderVectors3,
  149.     NULL
  150. };
  151.  
  152. struct IntuiText IText3 = {
  153.     2,0,JAM2,
  154.     -67,0,
  155.     NULL,
  156.     "Channel",
  157.     NULL
  158. };
  159.  
  160. struct Gadget ChannelGadget = {
  161.     &OctaveGadget,
  162.     95,15,
  163.     32,8,
  164.     GADGHCOMP,
  165.     LONGINT+RELVERIFY+STRINGCENTER,
  166.     STRGADGET,
  167.     (APTR)&Border3,
  168.     NULL,
  169.     &IText3,
  170.     0,
  171.     (APTR)&GadgetSI6,
  172.     6,
  173.     NULL
  174. };
  175.  
  176. USHORT BorderVectors4[] = {0,0,107,0,107,10,0,10,0,0};
  177. struct Border Border4 = {
  178.     -2,-1,
  179.     3,0,JAM1,
  180.     5,
  181.     BorderVectors4,
  182.     NULL
  183. };
  184.  
  185. struct IntuiText IText4 = {
  186.     1,0,JAM2,
  187.     12,1,
  188.     NULL,
  189.     "Cross Fade",
  190.     NULL
  191. };
  192.  
  193. struct Gadget CrossFadeGadget = {
  194.     &ChannelGadget,
  195.     23,41,
  196.     104,9,
  197.     GADGHCOMP,
  198.     RELVERIFY,
  199.     BOOLGADGET,
  200.     (APTR)&Border4,
  201.     NULL,
  202.     &IText4,
  203.     0,
  204.     NULL,
  205.     5,
  206.     NULL
  207. };
  208.  
  209. /* Gadget list */
  210.  
  211. struct NewWindow NewWindowStructure = {
  212.     0,0,
  213.     152,72,
  214.     0,1,
  215.     GADGETUP+CLOSEWINDOW+RAWKEY,
  216.     WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE
  217.     +ACTIVATE,
  218.     &CrossFadeGadget,
  219.     NULL,
  220.     " X Fade ",
  221.     NULL,
  222.     NULL,
  223.     30,20,
  224.     152,72,
  225.     WBENCHSCREEN
  226. };
  227.  
  228. unsigned short thisport;
  229. opencode(direction)
  230.  
  231. /*    There is nothing to be initialised.  However,
  232.     it would be nice to connect the console
  233.     keyboard to the sampler so the user can test
  234.     the cross fade loops, so make an OpenLink call.
  235.     FindMidiPort returns the port id, given the
  236.     name of the port.  Actually, these two ports
  237.     have ids that are hard coded into SoundScape.
  238.     This is an example what you should do with 
  239.     modules that are independantly loaded into 
  240.     the system.
  241. */
  242.  
  243. unsigned char direction;
  244.  
  245. {
  246.     OpenLink(FindMidiPort("console keyboard"),
  247.     FindMidiPort("sampler"));
  248.     return(1);
  249. }
  250.  
  251. closecode(direction)
  252.  
  253. unsigned char direction;
  254.  
  255. {
  256.     return(1);
  257. }
  258.  
  259. clearsounddata(sounddata)
  260.  
  261. /*    This routine frees up the sample buffer belonging
  262.     to the SoundData structure 'sounddata'.
  263. */
  264.  
  265. struct SoundData *sounddata;
  266.  
  267. {
  268.     if (sounddata->data) 
  269.     FreeMem(sounddata->data,sounddata->length);
  270.     sounddata->data = 0;
  271.     sounddata->length = 0;
  272.     sounddata->loopstart = 0;
  273.     sounddata->loopend = 0;
  274.     sounddata->start = 0;
  275. }
  276.  
  277. crossfade(sounddata)
  278.  
  279. /*    This, the cross fade routine, operates on a 
  280.     SoundData structure.
  281.  
  282.     The cross fade is done on the region of the
  283.     sample between the two loop points.  The
  284.     sample prior to the loop start is gradually
  285.     mixed in until it is in full force by the
  286.     end of the loop.  
  287.  
  288.     This is very straight forward, the only problem
  289.     encountered is a sample with a loop that 
  290.     is longer than the part leading into the
  291.     loop.  This is solved by having the cross fade
  292.     section be shorter - the length of the lead
  293.     in section.
  294. */
  295.     
  296. struct SoundData *sounddata;
  297.  
  298. {
  299.     char *sample;        /* Points to sample */
  300.     unsigned short loop;    /* Length of loop. */
  301.     unsigned short crosslength;    /* Length of cross fade. */
  302.     unsigned short start;    /* Start point. */
  303.     long result;        /* Intermediate result. */
  304.     unsigned short a,b;        /* Indexes into sample. */
  305.     unsigned short j;        /* Loop index. */
  306.     
  307.     loop = sounddata->loopend - sounddata->loopstart;
  308.     sample = &sounddata->data[sounddata->start];
  309.     start = sounddata->loopstart - sounddata->start;
  310.  
  311. /*    If the loop is greater than the start segment, set
  312.     the crossfade to cover the last part of the loop,
  313.     equal to the starting segment.
  314. */
  315.  
  316.     if (loop > start) {
  317.     crosslength = start;
  318.     a = 0;
  319.     b = loop;
  320.     }
  321.  
  322. /*    Otherwise, set the crossfade to cover the entire
  323.     loop.
  324. */
  325.  
  326.     else {
  327.     crosslength = loop;
  328.     a = start - loop;
  329.     b = start;
  330.     }
  331.     for (j = 0; j < crosslength; j++ ) {
  332.     result = (j * sample[a]);
  333.     result += (crosslength - j) * sample[b];
  334.     result = result / crosslength;
  335.     sample[b] = result;
  336.     a++;
  337.     b++;
  338.     }
  339. }
  340.  
  341. void useredit()
  342.  
  343. /*    This routine is called whenever the user clicks
  344.     twice on the cross fade icon.  A window is opened
  345.     and four gadgets are presented.  Two string
  346.     gadgets allow the user to select the octave and
  347.     channel of the sample they'd like to work on.
  348.     Two boolean gadgets are used to command the
  349.     cross fade and undo operations.
  350.  
  351.     There are two SoundData structures.  OldSound
  352.     is used to keep an old copy of the sample
  353.     around for undoing.  CFSound is used to hold
  354.     the sample that gets cross faded.
  355.  
  356.     RAWKEY events are passed on to the console
  357.     keyboard with the OutConsole command.
  358.     This is so the user can test the changed sound
  359.     without having to click on another window to
  360.     enable the Console Keyboard.
  361. */
  362.  
  363. {
  364.     struct IntuiMessage *message;
  365.     struct SoundData *oldsound, *cfsound;
  366.     short code, class;
  367.     struct Gadget *gadget;
  368.     struct Window *window;
  369.     short octave = 5;
  370.     short channel = 0;
  371.     oldsound = (struct SoundData *) 
  372.     AllocMem(sizeof(*oldsound),MEMF_CLEAR);
  373.     if (!oldsound) return;
  374.     cfsound = (struct SoundData *) 
  375.     AllocMem(sizeof(*cfsound),MEMF_CLEAR);
  376.     if (!cfsound) {
  377.     FreeMem(oldsound,sizeof(*oldsound));
  378.     return;
  379.     }
  380.     window = (struct Window *) 
  381.     OpenWindow(&NewWindowStructure);
  382.     while (window) {
  383.     while (!(message = (struct IntuiMessage *) 
  384.       GetMsg(window->UserPort)))
  385.         WaitPort(window->UserPort);
  386.     class = message->Class;
  387.     code = message->Code;
  388.     gadget = (struct Gadget *) message->IAddress;
  389.     ReplyMsg(message);
  390.     if (class == CLOSEWINDOW) break;
  391.     if (class == RAWKEY) OutConsole(code);
  392.     if (class == GADGETUP) {
  393.         switch (gadget->GadgetID) {
  394.         case 5 :
  395.  
  396. /*    The crossfade gadget.  Get the sample, using 
  397.     GetSoundData, and put it in cfsound.  Clear
  398.     the undo buffer (oldsound) and get the same
  399.     sample loaded into it.  Call crossfade to alter
  400.     cfsound, then install it in the sampler with
  401.     a call to SetSoundData.
  402.     Then, clear out cfsound.
  403. */
  404.     
  405.             if (!(GetSoundData(channel,
  406.               octave,cfsound))) {
  407.             clearsounddata(oldsound);
  408.             if (GetSoundData(channel,
  409.               octave,oldsound)) {
  410.                 oldsound->data = 0;
  411.             }
  412.             crossfade(cfsound);
  413.             SetSoundData(channel,octave,cfsound);
  414.             clearsounddata(cfsound);
  415.             }
  416.             break;
  417.         case 6 :
  418.  
  419. /*    This gadget simply sets the channel of the sampler
  420.     that we are looking at.  Also, clear the undo buffer.
  421. */
  422.  
  423.             channel = (GadgetSI6.LongInt - 1) & 0x0F;
  424.             clearsounddata(oldsound);
  425.             break;
  426.         case 7 :
  427.  
  428. /*    This gadget sets the octave of the sample we are
  429.     looking at.  Clear the undo buffer.
  430. */
  431.  
  432.             octave = GadgetSI7.LongInt;
  433.             if (octave < 0) octave = 0;
  434.             if (octave > 9) octave = 9;
  435.             clearsounddata(oldsound);
  436.             break;
  437.         case 8 :
  438.  
  439. /*    This is the undo command.  Simply give the undo
  440.     buffer to the sampler, then clear the undo buffer.
  441. */
  442.  
  443.             if (oldsound->data) {
  444.             SetSoundData(channel,octave,oldsound);
  445.             clearsounddata(oldsound);
  446.             }
  447.             break;
  448.         }
  449.     }
  450.     }
  451.     CloseWindow(window);
  452.     clearsounddata(oldsound);
  453.     clearsounddata(cfsound);
  454.     FreeMem(oldsound,sizeof(*oldsound));
  455.     FreeMem(cfsound,sizeof(*cfsound));
  456. }
  457.  
  458. editcode(direction,command,buffer)
  459.  
  460. /*    This is the edit routine provided to SoundScape 
  461.     in the AddMidiPort call.
  462.  
  463.     There is nothing in the way of data structures 
  464.     that we would like any other modules to access,
  465.     nor is there anything to save or load with
  466.     environment loads and save.  So, the GETSTATE, 
  467.     SETSTATE, SAVESTATE, and LOADSTATE commands are 
  468.     all ignored and the sample's length is set to
  469.     0.
  470.  
  471.     However, USEREDIT indicates the user has clicked 
  472.     twice on the cross fade icon and would like to 
  473.     work with it. In that case, call the routine 
  474.     'useredit' which puts up a window and lets the
  475.     user do that wild cross fade thing.
  476.     
  477. */
  478.  
  479. char direction, command;
  480. long *buffer;
  481.  
  482. {
  483.     static char not_editing = 1;
  484.     *buffer = 0;
  485.     switch (command) {
  486.     case USEREDIT :
  487.         if (not_editing) {
  488.         not_editing = 0;
  489.         useredit();
  490.         not_editing = 1;
  491.         }
  492.         break;
  493.     }
  494. }
  495.         
  496. /*    The main program is simple.  Just open SoundScape to
  497.     get the address of the library vector, then close
  498.     the library (since this is a module and usually is
  499.     invoked by SoundScape when the first program opens
  500.     SoundScape, if it keeps the library count up, there
  501.     will be no way to close SoundScape.)
  502.     Check the version number.  If it's below 2, this
  503.     SoundScape Sampler module doesn't support having
  504.     samples changed, so quit.
  505.     Else, add the module's port and wait for SoundScape
  506.     to shut it down.
  507. */
  508.  
  509. long SoundScapeBase;
  510. long IntuitionBase;
  511.  
  512. main() {
  513.     SoundScapeBase = OpenLibrary("soundscape.library",0);
  514.     if (SoundScapeBase) {
  515.     IntuitionBase = OpenLibrary("intuition.library",0);
  516.     CloseLibrary(SoundScapeBase);
  517.     if (Version() > 1) {
  518.         thisport = AddMidiPort(opencode,closecode,
  519.         editcode,0,&crossfadeimage,0,-1,"cross fade");    
  520.         SetTaskPri(FindTask(0),-20);
  521.         while (MidiPort(thisport)) Delay(100);
  522.     }
  523.     CloseLibrary(IntuitionBase);
  524.     }
  525. }
  526.